#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import glob
import shutil
import subprocess
import gi
import datetime
from pathlib import Path

# 确保GTK3和Pango可用
gi.require_version('Gtk', '3.0')
gi.require_version('GdkPixbuf', '2.0')
gi.require_version('Pango', '1.0')  # 新增：声明Pango版本
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib, Pango  # 新增：导入Pango

# 程序常量
APP_NAME = "PyMir"
APP_VERSION = "0.1.5"
COPYRIGHT_INFO = "© 2023 豆包. 保留所有权利。"
CONFIG_DIR = os.path.expanduser("~/.pymir")
COVER_DIR = os.path.join(CONFIG_DIR, "cover")
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.ini")
METADATA_FILE = os.path.join(CONFIG_DIR, "games_metadata.ini")
STATE_DIR = os.path.expanduser("~/.local/share/StrikerX3/Ymir/state/")
SUPPORTED_FORMATS = ('.iso', '.chd', '.cue', '.bin')
SUPPORTED_IMAGE_FORMATS = ('.png', '.jpg', '.jpeg', '.gif')

# 图标和默认封面路径
APP_ICON_PATH = "/opt/ymir/saturn.png"
DEFAULT_COVER_PATH = "/opt/ymir/saturn.png"
ICON_SIZE = 64  # 强制图标尺寸为64x64像素

# 自定义文件大小格式化函数
def human_readable_size(size, decimal_places=2):
    """将字节数转换为人类可读的格式"""
    units = ['B', 'KB', 'MB', 'GB', 'TB']
    size = float(size)
    
    if size == 0:
        return f"0 {units[0]}"
        
    for unit in units:
        if size < 1024 or unit == units[-1]:
            break
        size /= 1024
    
    return f"{size:.{decimal_places}f} {unit}"


class Config:
    """配置管理类"""
    def __init__(self):
        self.ymir_path = "ymir-sdl3"  # 默认程序路径
        self.rom_dir = os.path.expanduser("~")  # 默认ROM目录
        self.default_view = "list"  # 默认视图设置，list或grid
        
        # 确保配置目录存在
        os.makedirs(CONFIG_DIR, exist_ok=True)
        os.makedirs(COVER_DIR, exist_ok=True)
        os.makedirs(STATE_DIR, exist_ok=True)
        
        # 加载配置
        self.load()
    
    def load(self):
        """从配置文件加载设置"""
        if os.path.exists(CONFIG_FILE):
            try:
                with open(CONFIG_FILE, 'r') as f:
                    for line in f:
                        line = line.strip()
                        if '=' in line:
                            key, value = line.split('=', 1)
                            key = key.strip()
                            value = value.strip()
                            
                            if key == 'ymir_path':
                                self.ymir_path = value
                            elif key == 'rom_dir':
                                self.rom_dir = value
                            elif key == 'default_view':
                                if value in ['list', 'grid']:
                                    self.default_view = value
            except Exception as e:
                print(f"加载配置文件失败: {e}")
    
    def save(self):
        """保存配置到文件"""
        try:
            with open(CONFIG_FILE, 'w') as f:
                f.write(f"ymir_path={self.ymir_path}\n")
                f.write(f"rom_dir={self.rom_dir}\n")
                f.write(f"default_view={self.default_view}\n")
        except Exception as e:
            print(f"保存配置文件失败: {e}")


class MetadataManager:
    """游戏元数据管理类"""
    def __init__(self):
        self.metadata = {}  # 格式: {游戏路径: {备注名: ..., ...}}
        self.load()
    
    def load(self):
        """从文件加载元数据"""
        if os.path.exists(METADATA_FILE):
            try:
                with open(METADATA_FILE, 'r') as f:
                    current_path = None
                    for line in f:
                        line = line.strip()
                        if not line:
                            continue
                        if line.startswith('[') and line.endswith(']'):
                            current_path = line[1:-1]
                            self.metadata[current_path] = {}
                        elif '=' in line and current_path:
                            key, value = line.split('=', 1)
                            self.metadata[current_path][key.strip()] = value.strip()
            except Exception as e:
                print(f"加载元数据文件失败: {e}")
    
    def save(self):
        """保存元数据到文件"""
        try:
            with open(METADATA_FILE, 'w') as f:
                for path, data in self.metadata.items():
                    f.write(f"[{path}]\n")
                    for key, value in data.items():
                        f.write(f"{key}={value}\n")
                    f.write("\n")
        except Exception as e:
            print(f"保存元数据文件失败: {e}")
    
    def get_note(self, game_path):
        """获取游戏备注名"""
        return self.metadata.get(game_path, {}).get('note', '')
    
    def set_note(self, game_path, note):
        """设置游戏备注名"""
        if game_path not in self.metadata:
            self.metadata[game_path] = {}
        self.metadata[game_path]['note'] = note
        self.save()


class Game:
    """游戏信息类"""
    def __init__(self, path, metadata_manager):
        self.path = path
        self.filename = os.path.basename(path)
        self.base_name = os.path.splitext(self.filename)[0]
        self.metadata_manager = metadata_manager
        self.note = self.metadata_manager.get_note(path)
        self.name = self.note if self.note else self.base_name
        
        self.size = os.path.getsize(path)
        self.last_played = self.get_last_played()
        self.cover_path = self.get_cover_path()
    
    def get_last_played(self):
        """获取上次游玩时间"""
        try:
            mtime = os.path.getmtime(self.path)
            return datetime.datetime.fromtimestamp(mtime)
        except:
            return None
    
    def get_cover_path(self):
        """获取封面图片路径"""
        for ext in SUPPORTED_IMAGE_FORMATS:
            cover_path = os.path.join(COVER_DIR, self.base_name + ext)
            if os.path.exists(cover_path):
                return cover_path
        return DEFAULT_COVER_PATH if os.path.exists(DEFAULT_COVER_PATH) else None
    
    def get_size_human(self):
        """以人类可读的方式返回文件大小"""
        return human_readable_size(self.size)
    
    def get_last_played_str(self):
        """以字符串形式返回上次游玩时间"""
        if self.last_played:
            return self.last_played.strftime("%Y-%m-%d %H:%M")
        return "从未"
    
    def set_note(self, note):
        """设置游戏备注名"""
        self.metadata_manager.set_note(self.path, note)
        self.note = note
        self.name = self.note if self.note else self.base_name


class Statistics:
    """统计信息类"""
    @staticmethod
    def get_rom_stats(rom_dir):
        """获取ROM统计信息"""
        rom_count = 0
        rom_total_size = 0
        
        if not os.path.exists(rom_dir):
            return (rom_count, rom_total_size)
            
        for fmt in SUPPORTED_FORMATS:
            for file in glob.glob(os.path.join(rom_dir, f'*{fmt}'), recursive=True):
                rom_count += 1
                rom_total_size += os.path.getsize(file)
        
        return (rom_count, rom_total_size)
    
    @staticmethod
    def get_save_stats():
        """获取存档统计信息"""
        save_count = 0
        save_total_size = 0
        
        if not os.path.exists(STATE_DIR):
            return (save_count, save_total_size)
            
        for file in glob.glob(os.path.join(STATE_DIR, '*.bin')):
            save_count += 1
            save_total_size += os.path.getsize(file)
        
        return (save_count, save_total_size)


# 图标加载工具函数
def load_scaled_icon(icon_path):
    """加载图标并缩放到指定尺寸"""
    if not icon_path or not os.path.exists(icon_path):
        return None
        
    try:
        pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_path)
        scaled_pixbuf = pixbuf.scale_simple(
            ICON_SIZE, ICON_SIZE, 
            GdkPixbuf.InterpType.BILINEAR
        )
        return scaled_pixbuf
    except Exception as e:
        print(f"缩放图标失败: {e}")
        return None


class RenameDialog(Gtk.Dialog):
    """重命名对话框"""
    def __init__(self, parent, game):
        super().__init__(title="重命名游戏", transient_for=parent, flags=0)
        self.game = game
        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OK, Gtk.ResponseType.OK
        )
        
        self.set_default_size(300, 100)
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_icon(scaled_icon)
        
        box = self.get_content_area()
        box.set_border_width(10)
        box.set_spacing(5)
        
        label = Gtk.Label(label="请输入游戏的新名称:")
        box.add(label)
        
        self.entry = Gtk.Entry()
        self.entry.set_text(game.note if game.note else game.base_name)
        box.add(self.entry)
        
        self.show_all()
    
    def get_new_name(self):
        """获取新名称"""
        return self.entry.get_text().strip()


class SetCoverDialog(Gtk.Dialog):
    """设置封面对话框"""
    def __init__(self, parent, game):
        super().__init__(title="设置游戏封面", transient_for=parent, flags=0)
        self.game = game
        self.selected_image_path = None
        
        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OK, Gtk.ResponseType.OK
        )
        
        self.set_default_size(550, 450)
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_icon(scaled_icon)
        
        box = self.get_content_area()
        box.set_border_width(10)
        box.set_spacing(10)
        box.set_orientation(Gtk.Orientation.VERTICAL)
        
        browse_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        self.path_entry = Gtk.Entry()
        self.path_entry.set_placeholder_text("选择图片文件...")
        browse_btn = Gtk.Button(label="浏览...")
        browse_btn.connect("clicked", self.on_browse_clicked)
        
        browse_box.pack_start(self.path_entry, True, True, 0)
        browse_box.pack_start(browse_btn, False, False, 0)
        
        preview_frame = Gtk.Frame(label="预览")
        preview_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        preview_box.set_border_width(10)
        
        self.preview_image = Gtk.Image()
        cover_path = game.cover_path if game.cover_path else DEFAULT_COVER_PATH
        if cover_path and os.path.exists(cover_path):
            self.load_preview_image(cover_path)
        
        preview_box.pack_start(self.preview_image, True, True, 0)
        preview_frame.add(preview_box)
        
        box.pack_start(browse_box, False, False, 0)
        box.pack_start(preview_frame, True, True, 0)
        
        self.show_all()
    
    def on_browse_clicked(self, widget):
        """浏览图片文件"""
        dialog = Gtk.FileChooserDialog(
            title="选择封面图片",
            parent=self,
            action=Gtk.FileChooserAction.OPEN
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            dialog.set_icon(scaled_icon)
        
        filter_img = Gtk.FileFilter()
        filter_img.set_name("图片文件")
        for ext in SUPPORTED_IMAGE_FORMATS:
            filter_img.add_pattern(f'*{ext}')
        dialog.add_filter(filter_img)
        
        filter_all = Gtk.FileFilter()
        filter_all.set_name("所有文件")
        filter_all.add_pattern("*")
        dialog.add_filter(filter_all)
        
        if dialog.run() == Gtk.ResponseType.OK:
            image_path = dialog.get_filename()
            self.path_entry.set_text(image_path)
            self.load_preview_image(image_path)
            self.selected_image_path = image_path
        
        dialog.destroy()
    
    def load_preview_image(self, image_path):
        """加载并显示预览图片"""
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file(image_path)
            width = pixbuf.get_width()
            height = pixbuf.get_height()
            
            if width > height:
                max_size = 480
                if width > max_size:
                    scale = max_size / width
                    new_width = max_size
                    new_height = int(height * scale)
                else:
                    new_width = width
                    new_height = height
            elif height > width:
                max_height = 480
                if height > max_height:
                    scale = max_height / height
                    new_height = max_height
                    new_width = int(width * scale)
                else:
                    new_width = width
                    new_height = height
            else:
                max_size = 480
                if width > max_size:
                    new_width = max_size
                    new_height = max_size
                else:
                    new_width = width
                    new_height = height
            
            scaled_pixbuf = pixbuf.scale_simple(
                new_width, new_height, 
                GdkPixbuf.InterpType.BILINEAR
            )
            self.preview_image.set_from_pixbuf(scaled_pixbuf)
            
        except Exception as e:
            print(f"加载预览图片失败: {e}")
            self.preview_image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
    
    def apply_cover(self):
        """应用新封面"""
        if not self.selected_image_path:
            return False
            
        try:
            ext = os.path.splitext(self.selected_image_path)[1].lower()
            if ext not in SUPPORTED_IMAGE_FORMATS:
                return False
                
            target_path = os.path.join(COVER_DIR, self.game.base_name + ext)
            shutil.copy2(self.selected_image_path, target_path)
            self.game.cover_path = target_path
            return True
            
        except Exception as e:
            print(f"设置封面失败: {e}")
            return False


class GamePropertiesDialog(Gtk.Dialog):
    """游戏属性对话框"""
    def __init__(self, parent, game):
        super().__init__(title="游戏属性", transient_for=parent, flags=0)
        self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
        
        self.set_default_size(400, 300)
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_icon(scaled_icon)
        
        box = self.get_content_area()
        box.set_border_width(10)
        box.set_spacing(10)
        
        grid = Gtk.Grid()
        grid.set_column_spacing(10)
        grid.set_row_spacing(5)
        
        grid.attach(Gtk.Label(label="文件名:"), 0, 0, 1, 1)
        filename_label = Gtk.Label(label=game.filename)
        filename_label.set_selectable(True)
        grid.attach(filename_label, 1, 0, 1, 1)
        
        grid.attach(Gtk.Label(label="备注名:"), 0, 1, 1, 1)
        note_label = Gtk.Label(label=game.note if game.note else "无")
        note_label.set_selectable(True)
        grid.attach(note_label, 1, 1, 1, 1)
        
        grid.attach(Gtk.Label(label="文件路径:"), 0, 2, 1, 1)
        path_label = Gtk.Label(label=game.path)
        path_label.set_selectable(True)
        path_label.set_line_wrap(True)
        grid.attach(path_label, 1, 2, 1, 1)
        
        grid.attach(Gtk.Label(label="文件大小:"), 0, 3, 1, 1)
        size_label = Gtk.Label(label=game.get_size_human())
        grid.attach(size_label, 1, 3, 1, 1)
        
        grid.attach(Gtk.Label(label="上次游玩:"), 0, 4, 1, 1)
        played_label = Gtk.Label(label=game.get_last_played_str())
        grid.attach(played_label, 1, 4, 1, 1)
        
        grid.attach(Gtk.Label(label="封面状态:"), 0, 5, 1, 1)
        is_default_cover = game.cover_path == DEFAULT_COVER_PATH
        cover_status = "使用默认封面" if is_default_cover else "已设置自定义封面"
        cover_label = Gtk.Label(label=cover_status)
        grid.attach(cover_label, 1, 5, 1, 1)
        
        box.add(grid)
        self.show_all()


class SettingsDialog(Gtk.Dialog):
    """设置对话框"""
    def __init__(self, parent, config):
        super().__init__(title="设置", transient_for=parent, flags=0)
        self.config = config
        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OK, Gtk.ResponseType.OK
        )
        
        self.set_default_size(500, 300)
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_icon(scaled_icon)
        
        notebook = Gtk.Notebook()
        self.get_content_area().add(notebook)
        
        # 程序设置标签
        program_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        program_box.set_border_width(10)
        
        ymir_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        ymir_label = Gtk.Label(label="Ymir程序位置:")
        ymir_label.set_width_chars(15)
        self.ymir_entry = Gtk.Entry(text=self.config.ymir_path)
        ymir_button = Gtk.Button(label="浏览...")
        ymir_button.connect("clicked", self.on_ymir_browse_clicked)
        
        ymir_box.pack_start(ymir_label, False, False, 0)
        ymir_box.pack_start(self.ymir_entry, True, True, 0)
        ymir_box.pack_start(ymir_button, False, False, 0)
        
        rom_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        rom_label = Gtk.Label(label="游戏ROM位置:")
        rom_label.set_width_chars(15)
        self.rom_entry = Gtk.Entry(text=self.config.rom_dir)
        rom_button = Gtk.Button(label="浏览...")
        rom_button.connect("clicked", self.on_rom_browse_clicked)
        
        rom_box.pack_start(rom_label, False, False, 0)
        rom_box.pack_start(self.rom_entry, True, True, 0)
        rom_box.pack_start(rom_button, False, False, 0)
        
        program_box.pack_start(ymir_box, False, False, 0)
        program_box.pack_start(rom_box, False, False, 0)
        program_box.pack_start(Gtk.Label(), True, True, 0)
        
        notebook.append_page(program_box, Gtk.Label(label="程序"))
        
        # 统计信息标签
        stats_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        stats_box.set_border_width(10)
        
        rom_count, rom_size = Statistics.get_rom_stats(self.config.rom_dir)
        save_count, save_size = Statistics.get_save_stats()
        
        rom_label = Gtk.Label(label=f"游戏ROM总数: {rom_count} 个")
        rom_label.set_halign(Gtk.Align.START)
        rom_size_label = Gtk.Label(label=f"游戏ROM总大小: {human_readable_size(rom_size)}")
        rom_size_label.set_halign(Gtk.Align.START)
        save_label = Gtk.Label(label=f"游戏存档总数: {save_count} 个")
        save_label.set_halign(Gtk.Align.START)
        save_size_label = Gtk.Label(label=f"游戏存档总大小: {human_readable_size(save_size)}")
        save_size_label.set_halign(Gtk.Align.START)
        
        refresh_button = Gtk.Button(label="刷新统计")
        refresh_button.connect("clicked", self.on_refresh_stats)
        refresh_button.set_halign(Gtk.Align.START)
        
        stats_box.pack_start(rom_label, False, False, 0)
        stats_box.pack_start(rom_size_label, False, False, 0)
        stats_box.pack_start(Gtk.Label(), False, False, 5)
        stats_box.pack_start(save_label, False, False, 0)
        stats_box.pack_start(save_size_label, False, False, 0)
        stats_box.pack_start(Gtk.Label(), True, True, 0)
        stats_box.pack_start(refresh_button, False, False, 0)
        
        self.stats_widgets = {
            'rom_count': rom_label,
            'rom_size': rom_size_label,
            'save_count': save_label,
            'save_size': save_size_label
        }
        
        notebook.append_page(stats_box, Gtk.Label(label="统计"))
        
        # 视图设置标签页
        view_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        view_box.set_border_width(10)
        
        view_frame = Gtk.Frame(label="默认视图")
        view_frame.set_border_width(5)
        
        view_radio_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
        view_radio_box.set_border_width(5)
        
        self.list_radio = Gtk.RadioButton.new_with_label_from_widget(None, "列表视图")
        self.grid_radio = Gtk.RadioButton.new_with_label_from_widget(self.list_radio, "方格视图")
        
        if self.config.default_view == "list":
            self.list_radio.set_active(True)
        else:
            self.grid_radio.set_active(True)
        
        view_radio_box.pack_start(self.list_radio, False, False, 0)
        view_radio_box.pack_start(self.grid_radio, False, False, 0)
        
        view_frame.add(view_radio_box)
        view_box.pack_start(view_frame, False, False, 0)
        view_box.pack_start(Gtk.Label(), True, True, 0)
        
        notebook.append_page(view_box, Gtk.Label(label="视图"))
        
        self.show_all()
    
    def on_ymir_browse_clicked(self, widget):
        """浏览Ymir程序位置"""
        dialog = Gtk.FileChooserDialog(
            title="选择Ymir程序",
            parent=self,
            action=Gtk.FileChooserAction.OPEN
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            dialog.set_icon(scaled_icon)
        
        filter_exec = Gtk.FileFilter()
        filter_exec.set_name("可执行文件")
        filter_exec.add_mime_type("application/x-executable")
        filter_exec.add_pattern("*")
        dialog.add_filter(filter_exec)
        
        if dialog.run() == Gtk.ResponseType.OK:
            self.ymir_entry.set_text(dialog.get_filename())
        dialog.destroy()
    
    def on_rom_browse_clicked(self, widget):
        """浏览ROM目录"""
        dialog = Gtk.FileChooserDialog(
            title="选择ROM目录",
            parent=self,
            action=Gtk.FileChooserAction.SELECT_FOLDER
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            dialog.set_icon(scaled_icon)
        
        if dialog.run() == Gtk.ResponseType.OK:
            self.rom_entry.set_text(dialog.get_filename())
        dialog.destroy()
    
    def on_refresh_stats(self, widget):
        """刷新统计信息"""
        rom_count, rom_size = Statistics.get_rom_stats(self.config.rom_dir)
        save_count, save_size = Statistics.get_save_stats()
        
        self.stats_widgets['rom_count'].set_text(f"游戏ROM总数: {rom_count} 个")
        self.stats_widgets['rom_count'].set_halign(Gtk.Align.START)
        self.stats_widgets['rom_size'].set_text(f"游戏ROM总大小: {human_readable_size(rom_size)}")
        self.stats_widgets['rom_size'].set_halign(Gtk.Align.START)
        self.stats_widgets['save_count'].set_text(f"游戏存档总数: {save_count} 个")
        self.stats_widgets['save_count'].set_halign(Gtk.Align.START)
        self.stats_widgets['save_size'].set_text(f"游戏存档总大小: {human_readable_size(save_size)}")
        self.stats_widgets['save_size'].set_halign(Gtk.Align.START)
    
    def apply_settings(self):
        """应用设置"""
        self.config.ymir_path = self.ymir_entry.get_text()
        self.config.rom_dir = self.rom_entry.get_text()
        
        if self.list_radio.get_active():
            self.config.default_view = "list"
        else:
            self.config.default_view = "grid"
            
        self.config.save()


class AboutDialog(Gtk.AboutDialog):
    """关于对话框"""
    def __init__(self, parent):
        super().__init__(transient_for=parent, flags=0)
        self.set_program_name(APP_NAME)
        self.set_version(APP_VERSION)
        self.set_copyright(COPYRIGHT_INFO)
        self.set_comments("Saturn模拟器前端")
        self.set_website("https://example.com")
        self.set_website_label("官方网站")
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_logo(scaled_icon)
            self.set_icon(scaled_icon)
        else:
            self.set_logo_icon_name("emulator-frontend")
            
        self.connect("response", lambda dialog, response: dialog.destroy())


class GameContextMenu(Gtk.Menu):
    """游戏项右键菜单"""
    def __init__(self, main_window, game):
        super().__init__()
        self.main_window = main_window
        self.game = game
        
        rename_item = Gtk.MenuItem(label="重命名")
        rename_item.connect("activate", self.on_rename_activate)
        self.append(rename_item)
        
        cover_item = Gtk.MenuItem(label="设置封面")
        cover_item.connect("activate", self.on_cover_activate)
        self.append(cover_item)
        
        self.append(Gtk.SeparatorMenuItem())
        
        props_item = Gtk.MenuItem(label="游戏属性")
        props_item.connect("activate", self.on_properties_activate)
        self.append(props_item)
        
        self.show_all()
    
    def on_rename_activate(self, widget):
        """重命名菜单项激活"""
        dialog = RenameDialog(self.main_window, self.game)
        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            new_name = dialog.get_new_name()
            self.game.set_note(new_name)
            self.main_window.update_views(self.main_window.search_entry.get_text())
        
        dialog.destroy()
    
    def on_cover_activate(self, widget):
        """设置封面菜单项激活"""
        dialog = SetCoverDialog(self.main_window, self.game)
        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            if dialog.apply_cover():
                self.main_window.update_views(self.main_window.search_entry.get_text())
        
        dialog.destroy()
    
    def on_properties_activate(self, widget):
        """游戏属性菜单项激活"""
        dialog = GamePropertiesDialog(self.main_window, self.game)
        dialog.run()
        dialog.destroy()


class GameGridView(Gtk.FlowBox):
    """游戏方格视图 - 显示完整标题"""
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window
        self.set_valign(Gtk.Align.START)
        self.set_max_children_per_line(4)  # 减少每行显示数量
        self.set_min_children_per_line(1)
        self.set_row_spacing(15)  # 增加行间距
        self.set_column_spacing(15)  # 增加列间距
        self.set_selection_mode(Gtk.SelectionMode.NONE)
    
    def update_games(self, games):
        """更新游戏列表"""
        for child in self.get_children():
            self.remove(child)
        
        for game in games:
            self.add(self.create_game_item(game))
        
        self.show_all()
    
    def create_game_item(self, game):
        """创建游戏项 - 显示完整标题"""
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
        box.set_size_request(180, 240)  # 增加宽度和高度
        box.set_border_width(5)
        
        # 封面图片
        image = Gtk.Image()
        image.set_size_request(170, 180)  # 增加封面宽度
        
        cover_path = game.cover_path if game.cover_path else DEFAULT_COVER_PATH
        if cover_path and os.path.exists(cover_path):
            try:
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
                    cover_path,
                    170, 180,
                    True
                )
                image.set_from_pixbuf(pixbuf)
            except:
                scaled_icon = load_scaled_icon(APP_ICON_PATH)
                if scaled_icon:
                    image.set_from_pixbuf(scaled_icon)
                else:
                    image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
        else:
            scaled_icon = load_scaled_icon(APP_ICON_PATH)
            if scaled_icon:
                image.set_from_pixbuf(scaled_icon)
            else:
                image.set_from_icon_name("image-missing", Gtk.IconSize.DIALOG)
        
        # 游戏名称 - 使用GTK的Pango进行换行
        name_label = Gtk.Label()
        name_label.set_text(game.name)  # 显示完整标题
        name_label.set_line_wrap(True)  # 启用自动换行
        name_label.set_max_width_chars(20)  # 增加最大宽度字符数
        name_label.set_halign(Gtk.Align.CENTER)  # 保持居中对齐
        name_label.set_valign(Gtk.Align.START)  # 顶部对齐
        # 使用从gi.repository导入的Pango
        name_label.set_line_wrap_mode(Pango.WrapMode.WORD)  # 按单词换行
        
        # 添加到容器
        box.pack_start(image, False, False, 0)
        box.pack_start(name_label, False, False, 0)
        
        # 事件盒子，用于捕获鼠标事件
        event_box = Gtk.EventBox()
        event_box.add(box)
        event_box.connect("button-press-event", self.on_game_clicked, game)
        
        return event_box
    
    def on_game_clicked(self, widget, event, game):
        """游戏项点击事件"""
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.main_window.launch_game(game)
        elif event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
            menu = GameContextMenu(self.main_window, game)
            menu.popup_at_pointer(event)


class GameListModel(Gtk.ListStore):
    """游戏列表数据模型"""
    def __init__(self):
        super().__init__(str, str, str, object)  # 名称, 大小, 上次游玩, 游戏对象


class GameListView(Gtk.TreeView):
    """游戏列表视图"""
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window
        self.set_model(GameListModel())
        
        renderer_text = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("游戏标题", renderer_text, text=0)
        column.set_sort_column_id(0)
        self.append_column(column)
        
        renderer_text = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("游戏容量", renderer_text, text=1)
        column.set_sort_column_id(1)
        self.append_column(column)
        
        renderer_text = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("上次游戏时间", renderer_text, text=2)
        column.set_sort_column_id(2)
        self.append_column(column)
        
        self.connect("row-activated", self.on_row_activated)
        self.connect("button-press-event", self.on_button_press)
    
    def update_games(self, games):
        """更新游戏列表"""
        model = self.get_model()
        model.clear()
        
        for game in games:
            model.append([
                game.name,
                game.get_size_human(),
                game.get_last_played_str(),
                game
            ])
    
    def on_row_activated(self, treeview, path, column):
        """行激活事件（双击）"""
        model = treeview.get_model()
        game = model[path][3]
        self.main_window.launch_game(game)
    
    def on_button_press(self, treeview, event):
        """鼠标点击事件"""
        if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3:
            try:
                path, column, x, y = treeview.get_path_at_pos(int(event.x), int(event.y))
                treeview.get_selection().select_path(path)
                model = treeview.get_model()
                game = model[path][3]
                menu = GameContextMenu(self.main_window, game)
                menu.popup_at_pointer(event)
                return True
            except TypeError:
                pass
        return False


class MainWindow(Gtk.Window):
    """主窗口类"""
    def __init__(self):
        super().__init__(title=APP_NAME)
        self.config = Config()
        self.metadata_manager = MetadataManager()
        self.games = []
        self.current_view = self.config.default_view  # list 或 grid
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            self.set_icon(scaled_icon)
        else:
            print(f"无法加载窗口图标: {APP_ICON_PATH}")
        
        self.set_default_size(1024, 768)
        self.create_ui()
        self.load_games()
        self.apply_view_setting()
    
    def create_ui(self):
        """创建用户界面"""
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        self.add(main_box)
        
        menubar = self.create_menu_bar()
        main_box.pack_start(menubar, False, False, 0)
        
        tool_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
        tool_box.set_border_width(5)
        main_box.pack_start(tool_box, False, False, 0)
        
        self.view_button_box = Gtk.ButtonBox(orientation=Gtk.Orientation.HORIZONTAL)
        self.view_button_box.set_layout(Gtk.ButtonBoxStyle.START)
        
        self.list_view_btn = Gtk.Button(label="列表视图")
        self.grid_view_btn = Gtk.Button(label="方格视图")
        
        self.list_view_btn.connect("clicked", self.on_view_clicked, "list")
        self.grid_view_btn.connect("clicked", self.on_view_clicked, "grid")
        
        self.view_button_box.add(self.list_view_btn)
        self.view_button_box.add(self.grid_view_btn)
        
        search_container = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        self.search_entry = Gtk.SearchEntry()
        self.search_entry.set_placeholder_text("搜索游戏...")
        self.search_entry.connect("search-changed", self.on_search_changed)
        self.search_entry.set_max_width_chars(30)
        self.search_entry.set_width_chars(30)
        
        search_container.pack_end(self.search_entry, False, False, 0)
        
        tool_box.pack_start(self.view_button_box, False, False, 0)
        tool_box.pack_end(search_container, False, False, 0)
        
        self.view_stack = Gtk.Stack()
        self.view_stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        
        list_scroll = Gtk.ScrolledWindow()
        list_scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        
        grid_scroll = Gtk.ScrolledWindow()
        grid_scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        
        self.list_view = GameListView(self)
        self.grid_view = GameGridView(self)
        
        list_scroll.add(self.list_view)
        grid_scroll.add(self.grid_view)
        
        self.view_stack.add_titled(list_scroll, "list", "列表视图")
        self.view_stack.add_titled(grid_scroll, "grid", "方格视图")
        
        main_box.pack_start(self.view_stack, True, True, 0)
        
        self.status_bar = Gtk.Statusbar()
        self.status_context_id = self.status_bar.get_context_id("game_count")
        main_box.pack_start(self.status_bar, False, False, 0)
    
    def apply_view_setting(self):
        """应用视图设置"""
        if hasattr(self, 'view_stack'):
            if self.current_view == "list":
                self.list_view_btn.set_sensitive(False)
                self.grid_view_btn.set_sensitive(True)
            else:
                self.grid_view_btn.set_sensitive(False)
                self.list_view_btn.set_sensitive(True)
            
            self.view_stack.set_visible_child_name(self.current_view)
    
    def create_menu_bar(self):
        """创建菜单栏"""
        file_menu = Gtk.Menu()
        
        open_item = Gtk.MenuItem(label="打开游戏")
        open_item.connect("activate", self.on_open_game)
        file_menu.append(open_item)
        
        settings_item = Gtk.MenuItem(label="设置")
        settings_item.connect("activate", self.on_open_settings)
        file_menu.append(settings_item)
        
        file_menu.append(Gtk.SeparatorMenuItem())
        
        exit_item = Gtk.MenuItem(label="退出")
        exit_item.connect("activate", Gtk.main_quit)
        file_menu.append(exit_item)
        
        help_menu = Gtk.Menu()
        
        about_item = Gtk.MenuItem(label="关于")
        about_item.connect("activate", self.on_open_about)
        help_menu.append(about_item)
        
        menubar = Gtk.MenuBar()
        
        file_menu_btn = Gtk.MenuItem(label="文件")
        file_menu_btn.set_submenu(file_menu)
        menubar.append(file_menu_btn)
        
        help_menu_btn = Gtk.MenuItem(label="帮助")
        help_menu_btn.set_submenu(help_menu)
        menubar.append(help_menu_btn)
        
        return menubar
    
    def load_games(self):
        """加载游戏列表"""
        self.games = []
        
        if not os.path.exists(self.config.rom_dir):
            self.status_bar.push(self.status_context_id, "共计 0 个游戏")
            return
            
        for fmt in SUPPORTED_FORMATS:
            for file in glob.glob(os.path.join(self.config.rom_dir, f'*{fmt}'), recursive=True):
                try:
                    self.games.append(Game(file, self.metadata_manager))
                except Exception as e:
                    print(f"加载游戏失败 {file}: {e}")
        
        self.games.sort(key=lambda x: x.name)
        self.update_views()
        self.status_bar.push(self.status_context_id, f"共计 {len(self.games)} 个游戏")
    
    def update_views(self, filter_text=None):
        """更新视图显示"""
        if filter_text and filter_text.strip():
            filter_text = filter_text.lower()
            filtered_games = [
                game for game in self.games 
                if filter_text in game.name.lower()
            ]
        else:
            filtered_games = self.games
        
        self.list_view.update_games(filtered_games)
        self.grid_view.update_games(filtered_games)
        self.status_bar.push(self.status_context_id, f"共计 {len(filtered_games)} 个游戏")
    
    def launch_game(self, game):
        """启动游戏"""
        if not os.path.exists(self.config.ymir_path):
            dialog = Gtk.MessageDialog(
                parent=self,
                flags=0,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text="启动失败"
            )
            scaled_icon = load_scaled_icon(APP_ICON_PATH)
            if scaled_icon:
                dialog.set_icon(scaled_icon)
            dialog.format_secondary_text("Ymir程序未找到，请检查设置中的程序路径。")
            dialog.run()
            dialog.destroy()
            return
        
        if not os.path.exists(game.path):
            dialog = Gtk.MessageDialog(
                parent=self,
                flags=0,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text="启动失败"
            )
            scaled_icon = load_scaled_icon(APP_ICON_PATH)
            if scaled_icon:
                dialog.set_icon(scaled_icon)
            dialog.format_secondary_text(f"游戏文件不存在: {game.path}")
            dialog.run()
            dialog.destroy()
            return
        
        command = [self.config.ymir_path, game.path]
        
        try:
            subprocess.Popen(command)
            game.last_played = datetime.datetime.now()
            self.update_views(self.search_entry.get_text())
            
        except Exception as e:
            dialog = Gtk.MessageDialog(
                parent=self,
                flags=0,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text="启动失败"
            )
            scaled_icon = load_scaled_icon(APP_ICON_PATH)
            if scaled_icon:
                dialog.set_icon(scaled_icon)
            dialog.format_secondary_text(f"无法启动游戏: {str(e)}")
            dialog.run()
            dialog.destroy()
    
    def on_open_game(self, widget):
        """打开游戏文件对话框"""
        dialog = Gtk.FileChooserDialog(
            title="选择游戏ROM",
            parent=self,
            action=Gtk.FileChooserAction.OPEN
        )
        dialog.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN, Gtk.ResponseType.OK
        )
        
        scaled_icon = load_scaled_icon(APP_ICON_PATH)
        if scaled_icon:
            dialog.set_icon(scaled_icon)
        
        dialog.set_current_folder(self.config.rom_dir)
        
        filter_rom = Gtk.FileFilter()
        filter_rom.set_name("Saturn游戏文件")
        for fmt in SUPPORTED_FORMATS:
            filter_rom.add_pattern(f'*{fmt}')
        dialog.add_filter(filter_rom)
        
        filter_all = Gtk.FileFilter()
        filter_all.set_name("所有文件")
        filter_all.add_pattern("*")
        dialog.add_filter(filter_all)
        
        if dialog.run() == Gtk.ResponseType.OK:
            game_path = dialog.get_filename()
            try:
                game = Game(game_path, self.metadata_manager)
                self.launch_game(game)
                self.load_games()
            except Exception as e:
                print(f"无法加载游戏 {game_path}: {e}")
        
        dialog.destroy()
    
    def on_view_clicked(self, widget, view_type):
        """视图切换事件"""
        self.current_view = view_type
        self.view_stack.set_visible_child_name(view_type)
        
        if view_type == "list":
            self.list_view_btn.set_sensitive(False)
            self.grid_view_btn.set_sensitive(True)
        else:
            self.grid_view_btn.set_sensitive(False)
            self.list_view_btn.set_sensitive(True)
            
        self.config.default_view = view_type
        self.config.save()
    
    def on_search_changed(self, widget):
        """搜索框内容变化事件"""
        self.update_views(widget.get_text())
    
    def on_open_settings(self, widget):
        """打开设置对话框"""
        dialog = SettingsDialog(self, self.config)
        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            dialog.apply_settings()
            self.load_games()
            self.current_view = self.config.default_view
            self.apply_view_setting()
        
        dialog.destroy()
    
    def on_open_about(self, widget):
        """打开关于对话框"""
        dialog = AboutDialog(self)
        dialog.run()
        dialog.destroy()


if __name__ == "__main__":
    # 确保中文显示正常
    import locale
    locale.setlocale(locale.LC_ALL, '')
    
    window = MainWindow()
    window.connect("destroy", Gtk.main_quit)
    window.show_all()
    GLib.idle_add(window.apply_view_setting)
    Gtk.main()
